#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
#include <fstream>
#include <strings.h>
#include <stdlib.h>
#include <string>
#include <pthread.h>
#include "tlv.h"
#include "server.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>

using namespace std;

/* Catch Signal Handler functio */
void signal_callback_handler(int signum)
{
//        printf("Caught signal SIGPIPE %d\n",signum);
}



void socketTCP::processThreadProcess()
{
	int connFd = m_socket;
	cout << "Thread No: " << pthread_self() << endl;
	char test[30000];
	ReceiveBlock blockParser;
	m_active = true;

	while(true)
	{
		int data_len = read(connFd, test, 30000);

		if(data_len == 0)
		{
			m_active = false;
			break;
		}

		if(blockParser.parseData(test,data_len))
		{
			continue;
		}

		do {
			com::Block block;
			block.ParseFromString(blockParser.getBlock());
			m_server->dataReceive(block, this);

		} while(blockParser.nextBlock());

	}
	cout << "\nClosing thread and conn" << endl;
	close(connFd);

}
bool socketTCP::sendString(com::Block const& block)
{
	if(m_active)
	{
		std::string blockString;
		block.SerializeToString(&blockString);

		std::string data = sendBlock(blockString);
		pthread_mutex_lock(&m_send_block_mutex);
//		write(m_socket, data.c_str(), data.size());
//		std::cout << "send=" << data.size() << std::endl;
		send(m_socket,  data.c_str(), data.size(), 0);
		pthread_mutex_unlock(&m_send_block_mutex);
		return true;
	}
	return false;
};
socketTCP::socketTCP(int socket, serverTCP* server): m_socket(socket), m_server(server)
{
	pthread_mutex_init(&m_send_block_mutex, NULL);
}

void serverTCP::processThreadProcess()
{
	std::cout << "serverTCP::processThreadProcess" << std::endl;
	int  portNo, listenFd;
	struct sockaddr_in svrAdd, clntAdd;

	portNo = m_port;

	//create socket
	listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

	int on = 1;
	setsockopt( listenFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

	if(listenFd < 0)
	{
		cerr << "Cannot open socket" << endl;
		return;
	}

	bzero((char*) &svrAdd, sizeof(svrAdd));

	svrAdd.sin_family = AF_INET;
	svrAdd.sin_addr.s_addr = INADDR_ANY;
	svrAdd.sin_port = htons(portNo);

	//bind socket
	if(bind(listenFd, (struct sockaddr *)&svrAdd, sizeof(svrAdd)) < 0)
	{
		cerr << "Cannot bind" << endl;
		return;
	}

	listen(listenFd, 5);

	while (true)
	{
		socklen_t len = sizeof(clntAdd);

		cout << "Listening" << endl;

		int connFd;
		//this is where client connects. svr will hang in this mode until client conn
		connFd = accept(listenFd, (struct sockaddr *)&clntAdd, &len);
		std::cout << "connFd=" << connFd << std::endl;
		if (connFd < 0)
		{
			cerr << "Cannot accept connection" << endl;
			return;
		}
		else
		{
			cout << "Connection successful" << endl;
			new socketTCP(connFd, this);
		}
	}
}

serverTCP::serverTCP(int port): m_port(port)
{

	signal(SIGPIPE, signal_callback_handler);
}
/*
		void serverTCP::dataReceive(com::Block const& block, socketTCP* socket)
		{
			com::Block sendblock;
			socket->sendString(sendblock);
		}
*/

